package com.gkzf.ai.module.crm.service.creditreportsimple.app;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gkzf.ai.framework.common.pojo.CommonResult;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.admittancecondition.IncomeDebtRatioVo;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.admittancecondition.ProductIncomeDebtRatioVo;
import com.gkzf.ai.module.crm.controller.app.simpleCredit.vo.condition.UserAdmittanceConditionSaveReqVO;
import com.gkzf.ai.module.crm.dal.dataobject.creditreportsimple.UserAdmittanceConditionDO;
import com.gkzf.ai.module.crm.dal.dataobject.product.ProductAdmittanceConditionDO;
import com.gkzf.ai.module.crm.dal.dataobject.product.ProductMatchDO;
import com.gkzf.ai.module.crm.dal.mysql.product.ProductAdmittanceConditionMapper;
import com.gkzf.ai.module.crm.service.product.admin.ProductMatchService;
import com.gkzf.ai.module.crm.util.ExpressionEvaluator;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
@Service
@Slf4j
public class SimpleMatchServiceImpl implements SimpleMatchService{
    

    @Resource
    private AppUserAdmittanceConditionService conditionService;

    @Resource
    private ProductAdmittanceConditionMapper productAdmittanceConditionMapper;

    @Resource
    private ProductMatchService productMatchService;

    @Value("${productMatchUrl}")
    private String productMatchUrl;
    @Autowired
    private AppUserAdmittanceHouseService appUserAdmittanceHouseService;
    @Autowired
    private AppUserAdmittanceConditionService appUserAdmittanceConditionService;

    @Override
    public CommonResult<Object> matchProduct(String userOpenId) {
        /*
         * 获取收入负债比
         * 并更新
         */
        Map<String,String> incomeDebtRatio = getIncomeDebtRatio(userOpenId);
        if (!incomeDebtRatio.isEmpty()) {
            UserAdmittanceConditionSaveReqVO updateReqVO = new UserAdmittanceConditionSaveReqVO();
            updateReqVO.setUserOpenId(userOpenId);
            updateReqVO.setIncomeDebtRatio(incomeDebtRatio.get("incomeDebtRatio"));
            conditionService.updateUserAdmittanceConditionXml(updateReqVO);
        }
        String result = HttpUtil.get(productMatchUrl+"?cid=" + userOpenId);
        Map<String,Object> resultMap;
        try {
            resultMap = JSON.parseObject(result, new TypeReference<>() {});
        }catch (Exception e){
            return CommonResult.success(false,"匹配失败");
        }
        List<ProductMatchDO> productMatch = new ArrayList<>();
        List<ProductMatchDO> productMatchRepeat = new ArrayList<>();
        // 匹配成功产品
        extracted(userOpenId, resultMap, incomeDebtRatio, productMatch);
        // 匹配失败产品
        extracted(userOpenId, resultMap, productMatch, productMatchRepeat);
        productMatchService.insertProductMatch(productMatch,userOpenId);
        return CommonResult.success("匹配成功");
    }

    /**
     *  匹配产品
     * @param userOpenId 用户标识
     * @param resultMap 结果集
     * @param productMatch  判断是否重复 重复则_叠加描述
     * @param productMatchRepeat  存储收入负债比率是否重复
     */
    private void extracted(String userOpenId, Map<String, Object> resultMap, List<ProductMatchDO> productMatch, List<ProductMatchDO> productMatchRepeat) {
        insertProductMatch(resultMap,"failedReasons", object ->{
            if(object instanceof JSONArray jsonArray){
                Iterator<Object> iterator = jsonArray.stream().iterator();
                while (iterator.hasNext()){
                    Object next = iterator.next();
                    if (next instanceof JSONObject jsonObject){
                        /*
                         * 封装为对象
                         */
                        String productNo = jsonObject.getString("productNo");
                        String userDetail = jsonObject.getString("userDetail");
                        String productRequirement = jsonObject.getString("productRequirement");
                        String reason = jsonObject.getString("reason");
                        ProductMatchDO productMatchDO = new ProductMatchDO();
                        productMatchDO.setProductNo(productNo);
                        productMatchDO.setStatus(1);
                        productMatchDO.setCreditLimit("0");
                        productMatchDO.setUserCondition(userDetail);
                        productMatchDO.setProductCondition(productRequirement);
                        productMatchDO.setErrorResult(reason);
//                        productMatchDO.setUserOpenId(userOpenId);
                        boolean isProductNo = productMatch.stream().anyMatch(item -> item.getProductNo().equals(jsonObject.getString("productNo")));
                        if (reason.contains("收入负债比不匹配")){
                            productMatchRepeat.add(productMatchDO);
                        } else
                        if(isProductNo){
                            // 用来判断重复的集合
                            productMatch.stream().filter(item -> item.getProductNo().equals(productNo)).forEach(item -> {
                                item.setUserCondition(item.getUserCondition()+"_"+userDetail);
                                item.setProductCondition(item.getProductCondition()+"_"+productRequirement);
                                item.setErrorResult(item.getErrorResult()+"_"+reason);
                            });
                        }else {
                            productMatch.add(productMatchDO);
                        }
                    }
                }
            }

            List<String> idsInB = productMatch.stream()
                    .map(ProductMatchDO::getProductNo)
                    .toList();

            List<ProductMatchDO> diffById = productMatchRepeat.stream()
                    .filter(u -> !idsInB.contains(u.getProductNo()))
                    .toList();

            /*
               判断收入负债比
               当匹配失败就一个收入负债条件比时添加一组默认数据 避免直接跳过这个匹配
             */
            diffById.forEach(item -> {
                boolean anyMatch = productMatch.stream().anyMatch(it -> it.getProductNo().equals(item.getProductNo()));
                if (!anyMatch) {
                    ProductMatchDO productMatchDO = new ProductMatchDO();
                    productMatchDO.setProductNo(item.getProductNo());
                    productMatchDO.setStatus(1);
                    productMatchDO.setCreditLimit("0");
                    productMatchDO.setUserCondition("");
                    productMatchDO.setProductCondition("");
                    productMatchDO.setErrorResult("");
//                    productMatchDO.setUserOpenId(userOpenId);
                    productMatch.add(productMatchDO);
                }
            });


            extracted(productMatch, productMatchRepeat);
        });
    }


    /**
     *  封装 冗余代码 当出现匹配结果 重复时 去除重复的代码
     * @param productMatch 匹配结果
     * @param productMatchRepeat 匹配结果 重复
     */
    private static void extracted(List<ProductMatchDO> productMatch, List<ProductMatchDO> productMatchRepeat) {
        productMatch.forEach(item ->{
            List<ProductMatchDO> list = productMatchRepeat.stream().filter(it -> it.getProductNo().equals(item.getProductNo())).toList();
            if (!list.isEmpty()){
                if (list.size() == 1){
                    item.setUserCondition(convert().apply(item.getUserCondition())+list.get(0).getUserCondition());
                    item.setProductCondition(convert().apply(item.getProductCondition())+list.get(0).getProductCondition());
                    item.setErrorResult(convert().apply(item.getErrorResult())+list.get(0).getErrorResult());
                }else {
                    ProductMatchDO productMatchDO = list.stream().filter(ll -> !ll.getErrorResult().contains("前置条件不符合)")).findFirst().orElse(null);
                    if (productMatchDO != null){
                        item.setUserCondition(convert().apply(productMatchDO.getUserCondition())+productMatchDO.getUserCondition());
                        item.setProductCondition(convert().apply(item.getProductCondition())+productMatchDO.getProductCondition());
                        item.setErrorResult(convert().apply(item.getErrorResult())+productMatchDO.getErrorResult());
                    }else {
                        item.setUserCondition(convert().apply(item.getUserCondition())+list.get(0).getUserCondition());
                        item.setProductCondition(convert().apply(item.getProductCondition())+list.get(0).getProductCondition());
                        item.setErrorResult(convert().apply(item.getErrorResult())+list.get(0).getErrorResult());
                    }
                }
            }
        });
    }

    /**
     * 匹配成功 插入产品匹配
     * @param userOpenId 小程序银行标识
     * @param resultMap 结果
     * @param incomeDebtRatio 收支比
     * @param productMatch 匹配结果对象
     */
    private void extracted(String userOpenId, Map<String, Object> resultMap, Map<String, String> incomeDebtRatio, List<ProductMatchDO> productMatch) {
        insertProductMatch(resultMap,"passedProducts", object ->{
            if(object instanceof JSONObject jsonObject){
                for (Map.Entry<String, Object> next : jsonObject.entrySet()) {
                    ProductMatchDO productMatchDO = new ProductMatchDO();
                    productMatchDO.setProductNo(next.getKey());
                    productMatchDO.setStatus(0);
//                    productMatchDO.setUserOpenId(userOpenId);
                    if (incomeDebtRatio.containsKey(next.getKey())) {
                        productMatchDO.setCreditLimit(incomeDebtRatio.get(next.getKey()));
                    }
                    productMatch.add(productMatchDO);
                }
            }
        });
    }

    /**
     * 计算产品收入负债比
     * @param userOpenId userOpenId
     * @return 有额度产品的结果
     */
    @SneakyThrows
    public Map<String,String> getIncomeDebtRatio(String userOpenId) {
        Map<String,String> retuenMap = new HashMap<>();

        LambdaQueryWrapper<ProductAdmittanceConditionDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProductAdmittanceConditionDO::getIsIncomeDebtRatio,"1");
        /*
          获取产品准入中 所有选中收入负债比的产品
         */
        List<ProductAdmittanceConditionDO> admittanceConditionList = productAdmittanceConditionMapper.selectList(queryWrapper);
        List<IncomeDebtRatioVo> incomeDebtRatioVos = new ArrayList<>();
        UserAdmittanceConditionDO condition = appUserAdmittanceConditionService.getUserAdmittanceCondition(userOpenId);
        admittanceConditionList.forEach(item ->{

            /*
                解析产品公式
                将公式转换成具体对象
             */
            List<ProductIncomeDebtRatioVo> productIncomeDebtRatioVo = JSON.parseObject(item.getIncomeDebtRatio(), new TypeReference<>(){});
            log.info("解析产品编号:{} 解析收入负债比公式:{}",item.getNo(),item.getIncomeDebtRatio());
            /*
               循环公式 可能多个公式对应一个产品
             */
            productIncomeDebtRatioVo.forEach(productIncomeDebtRatio ->{
                IncomeDebtRatioVo incomeDebtRatioVo = new IncomeDebtRatioVo();
                /*
                    将公式中的中文条件值 替换成具体值
                 */
                replaceFormulaNoun(productIncomeDebtRatio.getDenominator(),condition);
                replaceFormulaNoun(productIncomeDebtRatio.getMolecule(),condition);
                if (listContainsChinese(productIncomeDebtRatio.getMolecule()) && listContainsChinese(productIncomeDebtRatio.getMolecule())){
                    retuenMap.put(item.getNo(),"简版征信报告：收入负债比要求数据无");
                    return;
                }
                /*
                    计算公式结果
                 */
                // 计算出 分子(负债)的总和
                BigDecimal molecule = ExpressionEvaluator.evaluate(productIncomeDebtRatio.getMolecule());
                log.info("分子结果：{}",molecule);
                // 计算出 分母(收入)的总和
                BigDecimal denominator = ExpressionEvaluator.evaluate(productIncomeDebtRatio.getDenominator());
                log.info("分母结果：{}",denominator);
                // 收入负债比结果
                String incomeDebtRatio = getIncomeDebtRatio(molecule, denominator);
                log.info("收入负债比结果：{}",incomeDebtRatio);
                // 组装这个公式的集合
                incomeDebtRatioVo.setUserRatio(incomeDebtRatio);
                incomeDebtRatioVo.setProductRatio(productIncomeDebtRatio.getResult());
                incomeDebtRatioVo.setRatio(productIncomeDebtRatio.getRatio());
                incomeDebtRatioVo.setProductNo(item.getNo());
                incomeDebtRatioVo.setIndex(productIncomeDebtRatio.getIndex());
                incomeDebtRatioVos.add(incomeDebtRatioVo);
            });
        });
        if (incomeDebtRatioVos.isEmpty()){
            return retuenMap;
        }
        retuenMap.put("incomeDebtRatio",JSON.toJSONString(incomeDebtRatioVos));
        return retuenMap;
    }


    /**
     * 计算收入负债比
     * @param molecule 分子
     * @param denominator 分母
     * @return 负债比值
     */
    private static String getIncomeDebtRatio(BigDecimal molecule, BigDecimal denominator) {
        String incomeDebtRatio = null;
        // 判断 如果分子(负债) 小于等于 0 则不计算 负债率 0%
        if (molecule.compareTo(BigDecimal.ZERO) <= 0){
            incomeDebtRatio = "0";
        }
        // 如果 分母(收入) 小于等于 0  则直接匹配不通过 负债率 100%
        else if (denominator.compareTo(BigDecimal.ZERO) <= 0 && molecule.compareTo(BigDecimal.ZERO) <= 0){
            incomeDebtRatio = "0";
        }// 如果 分母(收入) 小于等于 0 分子(收入)不等于0 则分母直接等于结果 则直接匹配不通过 负债率 100%
        else if (denominator.compareTo(BigDecimal.ZERO) <= 0 && molecule.compareTo(BigDecimal.ZERO) > 0){
            incomeDebtRatio = molecule.toString();
        }
        else {
            // 计算收入负债比 分子除分母 保留2位小数 四舍五入
            incomeDebtRatio = String.valueOf(molecule.divide(denominator,2, RoundingMode.HALF_UP));
        }
        return incomeDebtRatio;
    }

    /**
     *  替换 产品公式中的中文 换算成结果 替换中文字符
     * @param formulaNounList 公式集合
     */
    public void replaceFormulaNoun(List<String> formulaNounList,UserAdmittanceConditionDO condition) {
        for (int i = 0; i < formulaNounList.size(); i++) {
            String formulaNouns = formulaNounList.get(i);
            if (StringUtils.isEmpty(formulaNouns)){
                return;
            }
            String[] formulaNoun = formulaNouns.split(":");
            switch (formulaNoun[0]) {
                case "年收入":
                    BigDecimal annualIncome = appUserAdmittanceConditionService.getAnnualIncome(condition);
                    formulaNounList.set(i, annualIncome.toString());
                    break;
                case "月收入":
                    BigDecimal monthlyIncome = appUserAdmittanceConditionService.getMonthlyIncome(condition);
                    formulaNounList.set(i, monthlyIncome.toString());
                    break;
                case "认定月收入":
                    BigDecimal concludeMonthlyIncome = appUserAdmittanceConditionService.getConcludeMonthlyIncome(condition, formulaNoun[1]);
                    formulaNounList.set(i, concludeMonthlyIncome.toString());
                    break;
                default:
                    formulaNounList.set(i, "无匹配");
            }
        }
    }

    public void insertProductMatch(Map<String,Object> resultMap,String key, Consumer<Object> comsumer){
        if (resultMap.containsKey(key)){
            Object failedReasons = resultMap.get(key);
            comsumer.accept(failedReasons);

        }
    }


    /**
     * 为了可读性和效率，我们将 Unicode 区块预先定义在一个 Set 中。
     * Set.of() 是 Java 9+ 的语法，如果使用 Java 8，可以用 Arrays.asList 然后 new HashSet。
     */
    private static final Set<Character.UnicodeBlock> CHINESE_BLOCKS = Set.of(
            Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS,
            Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS,
            Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A,
            Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
    );

    /**
     * <b>[函数式改造]</b> 判断单个字符串是否包含中文字符
     *
     * @param str 要检查的字符串
     * @return 如果包含中文字符则返回 true，否则返回 false
     */
    public static boolean containsChinese(String str) {
        // 1. 前置条件检查，避免空指针
        if (str == null || str.isEmpty()) {
            return false;
        }
        // 2. 将字符串转换为 codePoints 流，然后使用 anyMatch 检查
        //    codePoints() 比 chars() 更能正确处理一些罕见的增补字符
        return str.codePoints().anyMatch(
                codePoint -> CHINESE_BLOCKS.contains(Character.UnicodeBlock.of(codePoint))
        );
    }
    /**
     * <b>[函数式改造]</b> 判断 List 集合中是否有任意一个字符串包含中文
     *
     * @param stringList 要检查的字符串列表
     * @return 如果有任意字符串包含中文则返回 true，否则返回 false
     */
    public static boolean listContainsChinese(List<String> stringList) {
        // 1. 前置条件检查
        if (stringList == null || stringList.isEmpty()) {
            return false;
        }
        // 2. 将列表转换为流，然后使用 anyMatch 检查
        //    这里使用了方法引用 (Method Reference)，它等同于 lambda: s -> containsChinese(s)
        return stringList.stream().anyMatch(SimpleMatchServiceImpl::containsChinese);
    }

    public static Function<String, String> convert() {
        // 1. 定义一个 BiFunction 来计算百分比率
        return  (numerator) -> {
            if (StringUtils.isNotBlank(numerator)){
                return numerator+"_";
            }else {
                return "";
            }
        };
    }
}
